const mouseEventHandler = makeSendPropertiesHandler([
  'ctrlKey',
  'metaKey',
  'shiftKey',
  'button',
  'pointerType',
  'clientX',
  'clientY',
  'pageX',
  'pageY'
])
const wheelEventHandlerImpl = makeSendPropertiesHandler(['deltaX', 'deltaY'])
const keydownEventHandler = makeSendPropertiesHandler(['ctrlKey', 'metaKey', 'shiftKey', 'keyCode'])

function wheelEventHandler(event, sendFn) {
  event.preventDefault()
  wheelEventHandlerImpl(event, sendFn)
}

function preventDefaultHandler(event) {
  event.preventDefault()
}

function copyProperties(src, properties, dst) {
  for (const name of properties) {
    dst[name] = src[name]
  }
}

function makeSendPropertiesHandler(properties) {
  return function sendProperties(event, sendFn) {
    const data = { type: event.type }
    copyProperties(event, properties, data)
    sendFn(data)
  }
}

function touchEventHandler(event, sendFn) {
  const touches = []
  const data = { type: event.type, touches }
  for (let i = 0; i < event.touches.length; ++i) {
    const touch = event.touches[i]
    touches.push({
      pageX: touch.pageX,
      pageY: touch.pageY
    })
  }

  sendFn(data)
}

// The four arrow keys
const orbitKeys = {
  37: true, // left
  38: true, // up
  39: true, // right
  40: true // down
}
function filteredKeydownEventHandler(event, sendFn) {
  const { keyCode } = event
  if (orbitKeys[keyCode]) {
    event.preventDefault()
    keydownEventHandler(event, sendFn)
  }
}

// 1个worker里管理多个 offscreen canvas 时用以区分不同的canvas
let nextProxyId = 0
class ElementProxyTransmitter {
  constructor(element, worker, eventHandlers) {
    this.worker = worker

    this.id = nextProxyId++
    // register an id
    // 1个worker里管理多个 offscreen canvas 时用以区分不同的canvas
    // worker.postMessage({
    //   type: 'makeProxy',
    //   id: this.id
    // })

    const sendSize = () => {
      const { devicePixelRatio } = window
      const rect = element.getBoundingClientRect()
      this.worker.postMessage({
        type: 'size',
        data: {
          devicePixelRatio, // 将devicePixelRatio传递给 worker
          left: rect.left,
          top: rect.top,
          width: element.clientWidth,
          height: element.clientHeight
        }
      })
    }
    sendSize()

    const sendEvent = (data) => {
      this.worker.postMessage({
        type: 'event',
        data
      })
    }
    for (const [eventName, handler] of Object.entries(eventHandlers)) {
      element.addEventListener(eventName, function (event) {
        handler(event, sendEvent)
      })
    }

    let resizeObserver = new ResizeObserver(sendSize)
    resizeObserver.observe(element)
    // TODO don't forget to clear
    // resizeObserver = resizeObserver.unobserve(target)
  }
}

const eventHandlers = {
  contextmenu: preventDefaultHandler,
  mousedown: mouseEventHandler,
  mousemove: mouseEventHandler,
  mouseup: mouseEventHandler,
  pointerdown: mouseEventHandler,
  pointermove: mouseEventHandler,
  pointerup: mouseEventHandler,
  touchstart: touchEventHandler,
  touchmove: touchEventHandler,
  touchend: touchEventHandler,
  wheel: wheelEventHandler,
  keydown: filteredKeydownEventHandler
}

export function createTransmitter(canvasElement, worker) {
  return new ElementProxyTransmitter(canvasElement, worker, eventHandlers)
}
